package org.xi.sims.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.stereotype.Service;
import org.xi.sims.base.service.impl.IBaseServiceImpl;
import org.xi.sims.config.exception.CloudException;
import org.xi.sims.pojo.entity.Timetable;
import org.xi.sims.pojo.form.SearchTimetableForm;
import org.xi.sims.pojo.form.TimetableForm;
import org.xi.sims.pojo.vo.CourseVO;
import org.xi.sims.pojo.vo.RoomVO;
import org.xi.sims.pojo.vo.TeacherVO;
import org.xi.sims.pojo.vo.TimetableVO;
import org.xi.sims.repository.TimetableRepository;
import org.xi.sims.service.*;
import org.xi.sims.util.XinUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author ：xi
 * @time ：Created in 19:11
 * @description：
 */
@Service
public class TimetableServiceImpl extends IBaseServiceImpl<Timetable, TimetableRepository> implements TimetableService {

    @Autowired
    @Lazy
    private StudentService studentService;
    @Autowired
    @Lazy
    private TeacherService teacherService;
    @Autowired
    @Lazy
    private RoomService roomService;
    @Autowired
    @Lazy
    private CourseService courseService;
    @Autowired
    @Lazy
    private GradeService gradeService;



    @Override
    public TimetableVO saveOrUpdate(TimetableForm form) {
        Timetable timetable = Timetable.builder().build();
        timetable.setWeek(form.getWeek());
        timetable.setKnob(form.getKnob());
        timetable.setRoomId(form.getRoomId());
        Example<Timetable> example = Example.of(timetable);
        Optional<Timetable> timetableOptional = repository.findOne(example);
        BeanUtil.copyProperties(form, timetable);
        if (XinUtil.isNull(timetableOptional)) {
            return vo(repository.save(timetable));
        }

        if (timetableOptional.isPresent()) {
            Timetable e = timetableOptional.get();
            if (XinUtil.noNull(form.getId())) {
                if (XinUtil.equal(e.getId(), form.getId())) {
                    return vo(repository.save(timetable));
                }
            }
            throw new CloudException("教学时间或教室冲突!");
        }
        return vo(repository.save(timetable));
    }

    @Override
    public List<TimetableVO> query(SearchTimetableForm form) {
        Timetable timetable = Timetable.builder().build();
        BeanUtil.copyProperties(form, timetable);
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withMatcher("gradeId", ExampleMatcher.GenericPropertyMatchers.contains())
                .withMatcher("courseId" ,ExampleMatcher.GenericPropertyMatchers.contains())
                .withMatcher("roomId" ,ExampleMatcher.GenericPropertyMatchers.contains())
                .withMatcher("teacherId" ,ExampleMatcher.GenericPropertyMatchers.contains());
        Example<Timetable> example = Example.of(timetable, matcher);

        return vos(repository.findAll(example));
    }

    @Override
    public List<TimetableVO> findVosByRoomId(Integer roomId) {
        return vos(repository.findByRoomId(roomId));
    }

    @Override
    public List<TimetableVO> findVosByTeacherId(Integer teacherId) {
        return vos(repository.findByTeacherId(teacherId));
    }

    @Override
    public List<Integer> findCourseIdByGradeId(Integer gradeId) {
        return findByGradeId(gradeId).stream().map(Timetable::getCourseId).collect(Collectors.toList());
    }

    @Override
    public List<Timetable> findByGradeId(Integer gradeId) {
        return repository.findByGradeId(gradeId);
    }

    @Override
    public boolean roomIsEmploy(Integer roomId) {
        return false;
    }

    @Override
    public List<TimetableVO> findVosByGradeId(Integer gradeId) {
        return vos(findByGradeId(gradeId));
    }

    @Override
    public List<TimetableVO> findVosByCourseId(Integer course) {
        return vos(repository.findByCourseId(course));
    }

    @Override
    public List<TimetableVO> findVoByStudentIdAndName(Integer studentId, String name) {
        Integer gradeId = studentService.findGradeIdById(studentId);
        if (XinUtil.isNull(gradeId)) {
            return ListUtil.empty();
        }
        List<Timetable> timetables = findByGradeId(gradeId);
        if (timetables.size() == 0) {
            return ListUtil.empty();
        }
        return new ArrayList<TimetableVO>(){{
            timetables.forEach(timetable -> {
                TeacherVO teacher = teacherService.findVoById(timetable.getTeacherId());
                RoomVO room = roomService.findVoById(timetable.getId());
                CourseVO course = courseService.findVoById(timetable.getCourseId());
                if (StrUtil.contains(teacher.getName(), name)
                        || StrUtil.contains(room.getLevel(), name)
                        || StrUtil.contains(course.getName(), name)
                ) {
                    TimetableVO vo = BeanUtil.copyProperties(timetable, TimetableVO.class);
                    vo.setTeacher(teacher);
                    vo.setRoom(room);
                    vo.setCourse(course);
                    this.add(vo);
                }
            });
        }};
    }

    @Override
    public List<TimetableVO> findVoByStudentId(Integer studentId) {
        Integer gradeId = studentService.findGradeIdById(studentId);
        if (XinUtil.isNull(gradeId)) {
            return ListUtil.empty();
        }
        List<Timetable> timetables = findByGradeId(gradeId);
        if (timetables.size() == 0) {
            return ListUtil.empty();
        }
        return vos(timetables);
    }

    @Override
    public TimetableVO vo(Timetable timetable) {
        TimetableVO vo = BeanUtil.copyProperties(timetable, TimetableVO.class);
        vo.setTeacher(teacherService.findVoById(timetable.getTeacherId()));
        vo.setRoom(roomService.findVoById(timetable.getRoomId()));
        vo.setCourse(courseService.findVoById(timetable.getCourseId()));
        vo.setGrade(gradeService.findVoById(timetable.getGradeId()));
        return vo;
    }

    @Override
    public List<TimetableVO> vos(List<Timetable> timetables) {
        return new ArrayList<TimetableVO>() {{
            timetables.forEach(timetable -> {
                this.add(vo(timetable));
            });
        }};
    }
}
